#include <driver/gpio.h>
#include <driver/rmt.h>
#include <freertos/queue.h>
#include <string.h>
#include "lwip/err.h"
#include "encoder_rmt.h"
#include "axis_monitor.h"
#include "wifi.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "serial.h"

static QueueHandle_t pkgQueue = NULL;

// 中断处理函数（必须放在 IRAM 中）
static void IRAM_ATTR gpio_isr_handler(void* arg) {
    PkgType_t pkgt;
    uint32_t gpio_num = ((uint32_t) arg)>>16;
    pkgt.val = ((uint32_t) arg)&0xffff;
    int8_t level = gpio_get_level(gpio_num);
    pkg_send(pkgt,esp_timer_get_time(),&level,1);
}

// 配置 GPIO 中断
void setup_gpio_interrupt(uint32_t gpio,PkgType_t pkgt) {
    // 1. 配置 GPIO 引脚
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << gpio),  // 要监视的引脚（例如 GPIO4）
        .mode = GPIO_MODE_INPUT,              // 输入模式
        .pull_up_en = GPIO_PULLUP_ENABLE,     // 使能上拉电阻（可选）
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_ANYEDGE        // 触发方式：任意边沿（上升沿+下降沿）
    };
    gpio_config(&io_conf);

    // 2. 安装 GPIO 中断服务
    gpio_install_isr_service(0);  // 参数 0 表示使用默认配置

    // 3. 添加中断处理函数
    gpio_isr_handler_add(gpio, gpio_isr_handler, (void*)(gpio<<16|pkgt.val));
}

void pkg_init(uint16_t size)
{
    if(pkgQueue)
        vQueueDelete(pkgQueue);

    pkgQueue =  xQueueCreate(size, sizeof(PkgAxisData_t*));
}

void pkg_release()
{
    if(pkgQueue)
    {
        vQueueDelete(pkgQueue);
        pkgQueue = NULL;
    }
}

void pkg_send(PkgType_t type, uint64_t tick, int8_t* data, uint16_t len)
{
    PkgAxisData_t *ppkg = (PkgAxisData_t *)malloc(sizeof(PkgAxisData_t) + len);
    if(ppkg) {
        ppkg->len = sizeof(PkgAxisData_t) + len;
        ppkg->pkg_type = type;
        ppkg->tick = tick;
        memcpy(ppkg->data, data, len);
        
        // 尝试发送到队列，如果队列满则丢弃数据包并释放内存
        if(xQueueSend(pkgQueue, &ppkg, 0) != pdPASS) {
            free(ppkg);
            // 可以在这里添加日志记录队列满的情况
        }
    }
}

void RmtReceiver(int8_t* buf,size_t n,uint8_t axis)
{
    PkgType_t pkgt;
    pkgt.val = axis;
    pkg_send(pkgt,esp_timer_get_time(),buf,n);
}

void accept_handler(int client_sock)
{
    PkgAxisData_t *ppkg;

    while(1)
    {
        // 等待队列中的数据，设置超时时间
        if(xQueueReceive(pkgQueue, &ppkg, 1000 / portTICK_PERIOD_MS) == pdTRUE)
        {
            int ret = send(client_sock, ppkg, ppkg->len, 0);
            free(ppkg); // 释放内存
            
            if (ret <= 0) {
                print("send failed: errno %d", errno);
                break;
            }
        }
    }

    close(client_sock);
    print("Connection closed\r\n");
}

void axis_monitor(uint8_t axis,gpio_num_t step_pin,gpio_num_t dir_pin,gpio_num_t enc_a,gpio_num_t enc_b)
{
    AxisMonitor_t * pam = (AxisMonitor_t*)malloc(sizeof(AxisMonitor_t));
    PkgType_t pkgtype;
    pkgtype.axis = axis;
    pam->step_pin = step_pin;
    pam->dir_pin = dir_pin;
    pam->enc_a = enc_a;
    pam->enc_b = enc_b;
    pkgtype.type = (uint8_t)TYPE_STEP;
    encoder_rmt_init(RMT_CHANNEL_0,step_pin,80,100,10,RmtReceiver,pkgtype.val);
    pkgtype.type = (uint8_t)TYPE_DIR;
    setup_gpio_interrupt(dir_pin,pkgtype);
    pkgtype.type = (uint8_t)TYPE_ENA;
    encoder_rmt_init(RMT_CHANNEL_1,enc_a,80,100,10,RmtReceiver,pkgtype.val);
    pkgtype.type = (uint8_t)TYPE_ENB;
    encoder_rmt_init(RMT_CHANNEL_2,enc_b,80,100,10,RmtReceiver,pkgtype.val);

    create_server(8181,accept_handler);
}